package com.sy.simpleegg.serialport.lyyegg

import android.util.Log
import com.sy.simpleegg.ext.logFile
import com.sy.simpleegg.serialport.base.BaseController
import com.sy.simpleegg.serialport.bean.ComData
import com.sy.simpleegg.serialport.util.ConvertHex
import com.sy.simpleegg.util.ByteUtil
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.cnbleu.serialport.SerialPort
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Queue
import java.util.concurrent.LinkedBlockingDeque
import kotlin.random.Random

abstract class BaseLyyEggController(
    portName: String,
    baudrate: SerialPort.BAUDRATE,
    stopb: SerialPort.STOPB,
    datab: SerialPort.DATAB,
    parity: SerialPort.PARITY,
    speed: Long?
) : BaseController(portName, baudrate, stopb, datab, parity, speed) {

    private val TAG = javaClass.simpleName

    private var dataHandlerJob: Job? = null
    private var dataLoop = true
    /**
     * 接收到的串口数据链表
     */
    private var dataQueue: Queue<ByteArray> = LinkedBlockingDeque()

    private val head = byteArrayOf(0xAA.toByte())
    private val end = byteArrayOf(0xDD.toByte())

    private val basicLen = 8

    private var tempHex = ""

    private var terminalConfigHex = "0100000000000000000000010001"//00 00 02 00 0000 00 0000 01 00 0100 01



    /**
     * 国家
     */
    private var countryHex = "01"

    private val HEAD = "AA"
    private val END = "DD"

//    private val FLAG_REC_HEART_BEAT = "01"
//    private val FLAG_UPLOAD_LIST = "14"
//    private val FLAG_REC_IN_INFO = "06"
//    private val FLAG_RESP_TERMINAL_CONFIG = "15"
//    private val FLAG_REC_OUT_INFO = "20"
//    private val FLAG_REC_CASH_CONFIG = "30"
//    private val FLAG_REC_MOTOR_CONFIG = "32"
//    private val FLAG_REC_ONDUTY_CONFIG = "35"
//    private val FLAG_REC_HISTORY_CONFIG = "37"
//    private val FLAG_REC_START_KIT = "D1"
//    private val FLAG_REC_SAVE = "D6"

    private val FLAG_REC_CONNECT = "01"
    private val FLAG_REC_UPLOAD_PKG = "01"
    private val FLAG_REC_PREPARE = "03"
    private val FLAG_REC_REMOTE = "04"
    private val FLAG_REC_RESULT = "05"

    private val childDev = 0x01.toByte()

    private var loginFlagHex = ""

    private var lastAmount: Long = 0
    private var lastNeedCoins: Long = 0

    init {
        openDataHandleJob()
    }

    private fun openDataHandleJob(){
        dataHandlerJob?.cancel()

        dataHandlerJob = mCoroutineScope.launch(Dispatchers.IO) {
            while (dataLoop) {
                try {
                    if (dataQueue.size > 0) {
                        var cmd: ByteArray? = null
                        while (dataQueue.poll().also { cmd = it } != null) {
                            val cmdHex = ConvertHex.byte2hex(cmd)
                            tempHex = handleSticky(tempHex + cmdHex)
                            if (tempHex.isNotEmpty()){
                                logFile("粘包数据：$tempHex")
                            }
                        }
                    }
                    delay(50L)
                } catch (e: Exception) {
                    e.printStackTrace()
                    logFile("串口数据处理异常：${e.message}")
                }
            }
        }
    }

    override fun onDataReceived(comData: ComData) {
        try {
//            val dataHex = ConvertHex.byte2hex(comData.data)
//            sticky(dataHex)
            dataQueue.add(comData.data)
        }catch (e: Exception){
            e.printStackTrace()
            logFile("接受数据异常：${e.message}")
        }
    }

    private fun sticky(dataHex: String){
        try {
            logFile("sticky数据：$dataHex")
            if (tempHex.isEmpty()){
                if (dataHex.startsWith("AA") && dataHex.endsWith("DD") && dataHex.length >= basicLen){
                    if (dataHex.contains("DDAA")){
                        val correctDataHex = dataHex.substring(0, dataHex.indexOf("DDAA") + 2)
                        val remainDataHex = dataHex.substring(dataHex.indexOf("DDAA") + 2)
                        if (verifyDataCompleted(correctDataHex)){
                            dataHandler(correctDataHex)
                            if (remainDataHex.isNotEmpty()) {
                                sticky(remainDataHex)
                            }
                        }else{
                            tempHex = correctDataHex
                            if (remainDataHex.isNotEmpty()) {
                                sticky(remainDataHex)
                            }
                        }
                    }else{
                        //完整数据帧
                        tempHex = ""
                        dataHandler(dataHex)
                    }
                }else if (dataHex.startsWith("AA") && !dataHex.contains("DDAA")){
                    //数据帧前半段
                    tempHex = dataHex
                }else if (dataHex.startsWith("AA") && dataHex.contains("DDAA")) {
                    val correctDataHex = dataHex.substring(0, dataHex.indexOf("DDAA") + 2)
                    val remainDataHex = dataHex.substring(dataHex.indexOf("DDAA") + 2)
                    if (verifyDataCompleted(correctDataHex)){
                        dataHandler(correctDataHex)
                        if (remainDataHex.isNotEmpty()) {
                            sticky(remainDataHex)
                        }
                    }else{
                        tempHex = correctDataHex
                        if (remainDataHex.isNotEmpty()) {
                            sticky(remainDataHex)
                        }
                    }
                }else{
                    logFile("收到无效数据：$dataHex")
                    tempHex = ""
                }
            }else{
                if (dataHex == "DD" || dataHex == "DDAA"){
                    val temp = tempHex + "DD"
                    if (verifyDataCompleted(temp)){
                        tempHex = ""
                        dataHandler(temp)
                    }else{
                        tempHex += dataHex
                    }
                }
                else {
                    if (dataHex.indexOf("DD") == -1){
                        tempHex += dataHex
                    }else{
                        val tempDataHex = dataHex
//                        do {
//                            val indexSub = tempDataHex.indexOf("DD")
//                            val subHex = tempDataHex.substring(0, indexSub + 2)
//                            tempDataHex = tempDataHex.substring(indexSub + 2)
//                            tempHex += subHex
//                            if (verifyDataCompleted(tempHex)){
//                                val resultHex = tempHex
//                                tempHex = ""
//                                dataHandler(resultHex)
//                                if (tempDataHex.isNotEmpty()) {
//                                    sticky(tempDataHex)
//                                }
//                            }else{
//                                if (tempDataHex.isNotEmpty()){
//                                    tempHex += tempDataHex
//                                    if (verifyDataCompleted(tempHex)){
//                                        val resultHex = tempHex
//                                        tempHex = ""
//                                        dataHandler(resultHex)
//                                    }else{
//                                        logFile("粘包数据：检验失败")
//                                    }
//                                }
//                            }
//
//                        }while (tempDataHex.indexOf("DD") != -1)

                        val dList: MutableList<Int> = mutableListOf()
                        val size = tempDataHex.length
                        //相邻两个字符都是D的索引
                        for (i in 0 until size){
                            val firstChar = tempDataHex.substring(i, i + 1) == "D"
                            if (i + 1 < size && firstChar){
                                if (tempDataHex.substring(i + 1, i + 2) == "D"){
                                    dList.add(i)
                                    logFile("相邻两个字符都是D的索引:$i")
                                }
                            }
                        }

                        run checkData@{
                            dList.forEachIndexed() { index, dIndex ->
                                val dHex = tempDataHex.substring(0, dIndex + 2)

                                val resultHex = tempHex + dHex
                                logFile("校验第 $index 个数据:$resultHex")
                                if (verifyDataCompleted(resultHex)){
                                    dataHandler(resultHex)
                                    val remainHex = tempDataHex.substring(dIndex + 2)
                                    if (remainHex.isNotEmpty()){
                                        if (remainHex.length > 1 && remainHex.startsWith("AA")){
                                            tempHex = remainHex
                                        }else if (remainHex == "A"){
                                            tempHex = remainHex
                                        }else{
                                            tempHex = ""
                                        }
                                    }else{
                                        tempHex = ""
                                    }
                                    return@checkData
                                }
                            }
                            tempHex += tempDataHex
                            logFile("接收数据不匹配：$dataHex, 拼接后数据为：$tempHex")
                        }
                    }
                }
            }
        }catch (e: Exception){
            e.printStackTrace()
            logFile("处理数据粘包异常：${e.message}")
        }
    }

    private fun handleSticky(dataHex: String): String{
        return try {
            logFile("处理数据：$dataHex")
            if (dataHex.startsWith("AA")){
                //数据帧头正确
                if (dataHex.contains("DD")){
                    //数据帧内包含帧头帧尾，需要进一步校验数据
                    val endIndexList = getMatchWordIndex(dataHex, "DD")
                    endIndexList.forEach { endIndex ->
                        val verifyDataHex = dataHex.substring(0, endIndex + 2)
                        //校验数据长度
                        if (verifyDataLen(verifyDataHex)){
                            //符合数据帧长度，校验 校验码
                            if (verifyDataXorCode(verifyDataHex)){
                                //校验正确，处理数据帧
                                dataHandler(verifyDataHex)
                            }
                            //不管校验正确还是失败，校验结束后继续处理剩余的数据
                            val remainDataHex = dataHex.substring(endIndex + 2)
                            return if (remainDataHex.isNotEmpty()) handleSticky(remainDataHex) else ""
                        }else{
                            //不符合长度标准，进入下一个循环继续校验
                            logFile("不符合长度标准，进入下一个循环继续校验$dataHex")
                        }
                    }
                    dataHex
                }else{
                    //不包含帧尾，需要校验数据长度
                    val currentDataLen = dataHex.length
                    if (currentDataLen >= 4){
                        val dataAreaLen = dataHex.substring(2, 4).toLong(16)
                        val completeDataLen = dataAreaLen*2 + 6
                        if (currentDataLen <= completeDataLen - 2){
                            //当前数据长度 小于 完整数据长度-帧尾，说明数据不完整，等待后续拼接数据帧
                            dataHex
                        }else{
                            //当前数据既不包含帧尾AB，长度也不符合协议标准，数据异常数据，直接清空该数据不处理
                            ""
                        }
                    }else{
                        //数据长度不足，拿不到完整数据帧的长度数据，直接返回，等待后续拼接数据帧
                        dataHex
                    }
                }
            }else{
                //数据帧头异常，直接清空数据，不处理
                ""
            }
        }catch (e: Exception){
            e.printStackTrace()
            logFile("粘包数据:$dataHex 处理异常：${e.message}")
            ""
        }
    }

    /**
     * 校验数据帧的xorCode
     * @param dataHex 校验的数据帧
     */
    private fun verifyDataXorCode(dataHex: String): Boolean{
        return try {
            val xorHex = dataHex.substring(dataHex.length - 4, dataHex.length - 2)
            val checkHex = dataHex.substring(2, dataHex.length - 4)
            val verifyXorHex = ByteUtil.bytes2HexStr(byteArrayOf(ByteUtil.getXor(ByteUtil.hexStr2bytes(checkHex))))
            logFile("数据校验位=$xorHex 计算校验位=$verifyXorHex checkHex=$checkHex")
            xorHex == verifyXorHex
        }catch (e: Exception){
            e.printStackTrace()
            logFile("校验数据xorCode异常：${e.message}")
            false
        }
    }

    /**
     * 校验有数据帧头帧尾的数据长度
     * @param dataHex 数据
     */
    private fun verifyDataLen(dataHex: String): Boolean{
        return try {
            val dataLen = dataHex.length.toLong()
            if (dataLen >= 12){
                val completeAreaDataLen = dataHex.substring(2, 4).toLong(16)
                val completeDataLen = completeAreaDataLen*2 + 6
                dataLen == completeDataLen
            }else{
                false
            }
        }catch (e: Exception){
            e.printStackTrace()
            logFile("校验数据长度异常：${e.message}")
            false
        }
    }

    /**
     * 获取相同字符的index
     * @param content 内容
     * @param word 匹配字符
     */
    private fun getMatchWordIndex(content: String, word: String): MutableList<Int>{
        return try {
            if (content.isEmpty() || word.isEmpty()) return mutableListOf()
            if (content.length < word.length) return mutableListOf()
            val contentLen = content.length
            val wordLen = word.length
            var lastIndex = 0
            var tempIndex = 0

            if (content.indexOf(word) == -1){
                mutableListOf()
            }else{
                val wordIndexList: MutableList<Int> = mutableListOf()
                var temp = content
                do {
                    val index = temp.indexOf(word)

                    if (index % 2 == 0){
                        tempIndex = 0
                        wordIndexList.add(lastIndex + index)
                        lastIndex = index + wordLen
                        temp = temp.substring(lastIndex)
                    }else{
                        //index单数
                        if (index < temp.length - 1) {
                            tempIndex = index + 1
                            lastIndex = index + 1
                            temp = temp.substring(tempIndex)
                        }
                    }

//                    wordIndexList.add(lastIndex + index)
//                    lastIndex = index + wordLen
//                    temp = temp.substring(lastIndex)
                }while (temp.indexOf(word) != -1)
                wordIndexList
            }
        }catch (e: Exception){
            e.printStackTrace()
            mutableListOf<Int>()
        }
    }

    private fun dataHandler(dataHex: String){
        logFile("完整数据：$dataHex")
        val len = dataHex.substring(2, 4).toInt(16)
        val indexHex = dataHex.substring(4, 6)

        if (indexHex != "02"){
            return
        }
        val cmdHex = dataHex.substring(6, 8)
        when (cmdHex){
            FLAG_REC_CONNECT -> {
                //链接状态
                val flagHex = dataHex.substring(8, 12)
                loginFlagHex = flagHex
                onConnect()
            }
            "CC" -> {
                val childDevIdHex = dataHex.substring(8, 10)
                val subCmdHex = dataHex.substring(10, 12)
                when (subCmdHex){
                    FLAG_REC_UPLOAD_PKG -> {
                        //主板主动上传状态（币数套餐）
                        val childDevIdHex = dataHex.substring(8, 10)
                        val sortSumHex = dataHex.substring(40, 42)
                        if (childDevIdHex == "01") {
                            respUploadPkg(childDevIdHex, sortSumHex)
                        }
                    }

                    FLAG_REC_PREPARE -> {
                        //云上分申请响应
                        val sortHex = dataHex.substring(12, 14)
                        val snHex = dataHex.substring(14, 26)
                        val stateHex = dataHex.substring(26, 28)
                        onRecPrepare(stateHex == "00")
                    }

                    FLAG_REC_REMOTE -> {
                        //云上分响应
                        val sortHex = dataHex.substring(12, 14)
                        val snHex = dataHex.substring(14, 26)
                        val quantity = "${dataHex.substring(28, 30)}${dataHex.substring(26, 28)}".toInt(16)
                        onOutResult(quantity > 0)

                    }
                    FLAG_REC_RESULT -> {
                        //云上分结果上传
                        val sortHex = dataHex.substring(12, 14)
                        val snHex = dataHex.substring(14, 26)
                        val quantity = "${dataHex.substring(28, 30)}${dataHex.substring(26, 28)}".toInt(16)
                        val result = quantity > 0
                        respResult(childDevIdHex, sortHex, snHex)
                    }
                }
            }
        }
    }

    /**
     * 校验数据完整性
     * @param dataHex 待校验数据
     */
    private fun verifyDataCompleted(dataHex: String): Boolean{
        return try {
            dataHex.run {
                if (isEmpty()){
                    return@run false
                }
                if (length < basicLen){
                    logFile("长度不匹配")
                    return@run false
                }
                if (!startsWith("AA")){
                    logFile("起始不为AA")
                    return@run false
                }
                if (!endsWith("DD")){
                    logFile("结尾不为DD")
                    return@run false
                }
                val lenHex = substring(2, 4)
                val len = lenHex.toInt(16)
                val dataLength = (len*2) + 6
                if (dataHex.length != dataLength){
                    logFile("长度不匹配2 len=$len dataLength=$dataLength")
                    return@run false
                }
                val xorHex = dataHex.substring(dataHex.length - 4, dataHex.length - 2)
                val checkHex = dataHex.substring(2, dataHex.length - 4)
                val verifyXorHex = ByteUtil.bytes2HexStr(byteArrayOf(ByteUtil.getXor(ByteUtil.hexStr2bytes(checkHex))))
//                logFile("数据校验位=$xorHex 计算校验位=$verifyXorHex checkHex=$checkHex")
                xorHex == verifyXorHex
            }
        }catch (e: Exception){
            e.printStackTrace()
            logFile("校验数据完整性异常：${e.message}")
            false
        }
    }

    /**
     * 链接状态
     */
    fun connect(){
        val preBytes = byteArrayOf(0x0B.toByte(), 0x01, 0x01)
        val devIdBytes = byteArrayOf(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01)
        val checkDataBytes = ByteUtil.combineBytes(preBytes, devIdBytes)
        val checkBytes = byteArrayOf(ByteUtil.getXor(checkDataBytes))
        val result = ByteUtil.combineBytes(checkDataBytes, checkBytes)
        sendByte(result)
    }

    /**
     * 支付申请
     * @param sort 仓位
     */
    fun prepareOut(sort: Int, sn: String){
        val preBytes = byteArrayOf(0x0C.toByte(), 0x01, 0xCC.toByte(), childDev, 0x03)
        val sortBytes = ByteUtil.hexToByteArray(ByteUtil.int2HexStr(sort, 2, false)!!)!!
        val snBytes = ByteUtil.hexToByteArray(ByteUtil.str2HexStr(sn, 12)!!)!!
        val checkDataBytes = ByteUtil.combineBytes(preBytes, sortBytes, snBytes)
        val checkBytes = byteArrayOf(ByteUtil.getXor(checkDataBytes))
        val result = ByteUtil.combineBytes(checkDataBytes, checkBytes)
        sendByte(result)
    }

    /**
     * 出货
     * @param sort 仓位
     */
    fun out(sort: Int, sn: String, quantity: Int = 1){
        val preBytes = byteArrayOf(0x0E.toByte(), 0x01, 0xCC.toByte(), childDev, 0x04)
        val sortBytes = ByteUtil.hexToByteArray(ByteUtil.int2HexStr(sort, 2, false)!!)!!
        val snBytes = ByteUtil.hexToByteArray(ByteUtil.str2HexStr(sn, 12)!!)!!
        val quantityBytes = ByteUtil.hexToByteArray(ByteUtil.int2HexStr(quantity, 4, true)!!)!!
        val checkDataBytes = ByteUtil.combineBytes(preBytes, sortBytes, snBytes, quantityBytes)
        val checkBytes = byteArrayOf(ByteUtil.getXor(checkDataBytes))
        val result = ByteUtil.combineBytes(checkDataBytes, checkBytes)
        sendByte(result)
    }

    /**
     * 自动响应云上分结果上传
     */
    private fun respResult(childDevIdHex: String, sortHex: String, snHex: String){
        val childDebByte = childDevIdHex.toInt(16).toByte()
        val preBytes = byteArrayOf(0x0C.toByte(), 0x01, 0xCC.toByte(), childDebByte, 0x05)
        val sortBytes = ByteUtil.hexToByteArray(sortHex)!!
        val snBytes = ByteUtil.hexToByteArray(snHex)!!
        val checkDataBytes = ByteUtil.combineBytes(preBytes, sortBytes, snBytes)
        val checkBytes = byteArrayOf(ByteUtil.getXor(checkDataBytes))
        val result = ByteUtil.combineBytes(checkDataBytes, checkBytes)
        sendByte(result)
    }

    /**
     * 自动响主板主动上传状态（币数套餐）
     */
    private fun respUploadPkg(childDevIdHex: String, sortSumHex: String){
        val childDevByte = childDevIdHex.toInt(16).toByte()
        val preBytes = byteArrayOf(0x06, 0x01, 0xCC.toByte(), childDevByte, 0x01)
        val sortSumBytes = ByteUtil.hexToByteArray(sortSumHex)!!
        val checkDataBytes = ByteUtil.combineBytes(preBytes, sortSumBytes)
        val checkBytes = byteArrayOf(ByteUtil.getXor(checkDataBytes))
        val result = ByteUtil.combineBytes(checkDataBytes, checkBytes)
        sendByte(result)
    }

    /**
     * 链接状态
     */
    abstract fun onConnect()

    /**
     * 收到控制板出币准备状态
     * @param success
     */
    abstract fun onRecPrepare(success: Boolean)

    /**
     * 出货结果
     * @param success
     */
    abstract fun onOutResult(success: Boolean)

    /**
     * 发送数据
     */
    private fun sendByte(dataBytes: ByteArray){
        try {
//            val crcCode = CRC16.crc16Checkout(dataBytes)
            val result = ByteUtil.combineBytes(head, dataBytes, end)
            sendData(result, 0)
        }catch (e: Exception){
            logFile("sendByte 发送指令异常：${e.message}")
        }
    }



    private fun getRandom(): Int{
        return Random.nextInt(256)
    }

    private fun createSn(sn: String): String{
        return try {
            var tempSn = ByteUtil.str2HexString(sn)
            while (tempSn.length < 64){
                tempSn = "0$tempSn"
            }
            tempSn
        }catch (e: Exception){
            e.printStackTrace()
            logFile("生成货道订单号异常：${e.message}")
            var result = "0"
            while (result.length < 64){
                result = "0$result"
            }
            result
        }
    }

    fun unRepeatSixCode(): String {
        return try {
            var sixChar = ""
            val sdf = SimpleDateFormat("yyMMddHHmmss")
            val date = Date()
            val time = sdf.format(date)
            for (i in 0 until time.length / 2) {
                var singleChar: String
                val x = time.substring(i * 2, (i + 1) * 2)
                val b = x.toInt()
                singleChar = if (b < 10) {
                    Integer.toHexString(x.toInt())
                } else if (b >= 10 && b < 36) {
                    (x.toInt() + 55).toChar().toString()
                } else {
                    (x.toInt() + 61).toChar().toString()
                }
                sixChar = sixChar + singleChar
            }
            Log.d(javaClass.simpleName, "生成一个6位不可重复的字符编码是：$sixChar")
            sixChar
        }catch (e: Exception){
            e.printStackTrace()
            "aaaaaa"
        }
    }

    private fun reverseHex(hexStr: String): String{
        return try {
            if (hexStr.isEmpty()){
                return ""
            }
            var tempHex = hexStr
            while (tempHex.length%2 != 0){
                tempHex += "0"
            }
            var result = ""
            for (i in tempHex.indices step 2){
                result = tempHex.substring(i, i + 2) + result
            }
            result
        }catch (e: Exception){
            e.printStackTrace()
            hexStr
        }
    }

    protected fun releaseBase(){
        dataLoop = false
    }

}